package com.glinsoft.ticktak.config;


import com.glinsoft.ticktak.config.cache.Cache;
import com.glinsoft.ticktak.config.cache.CacheProvider;
import com.glinsoft.ticktak.config.cache.NoCache;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.annotation.Autowired;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

@Aspect
@Configuration
@Slf4j
public class CacheLocalAdvice {

    @Autowired
    private CacheProvider cacheProvider;


    /** 是否启用数据缓存 **/
    private final boolean enableDataCache = !AppConsts.DEBUG_MODE;

    /** 需要缓存方法前缀（必须全部设置为小写） **/
    private List<String> queryMethodPrefixList = Arrays.asList(
            "get",
            "find",
            "select",
            "query",
            "count",
            "list",
            "page"
    );


    @Pointcut("execution(public * com.glinsoft.ticktakcg.entity.so.*.*(..)) || execution(public * com.glinsoft.ticktakcg.service.*.*.*(..))")
    public void useCache(){

    }

    @Around("useCache()")
    public Object aroundOperation(ProceedingJoinPoint thisJoinPoint) throws Throwable{
        if(!enableDataCache){
            return thisJoinPoint.proceed();
        }
        String method = ((MethodSignature) thisJoinPoint.getSignature()).getMethod().getName();
        String key = getMethodKey(thisJoinPoint);
        if(!isQueryMethod(method)){
            return thisJoinPoint.proceed();
        }
        MethodSignature sign = (MethodSignature) thisJoinPoint.getSignature();
        Method exeMethod = sign.getMethod();
        if(exeMethod.isAnnotationPresent(NoCache.class)){
            log.debug("==> NoCache, 未使用缓存, Method:{}",method);
            return thisJoinPoint.proceed();
        }
        Cache cache = cacheProvider.getCache();
        Object t = cache.getValue(key);
        if(t != null){
            return t;
        }
        t = thisJoinPoint.proceed();
        cache.setValue(key,t);
        return t;
    }

    private boolean isQueryMethod(String methodName){
        for(String prefix : queryMethodPrefixList){
            if(methodName.toLowerCase().startsWith(prefix)){
                return true;
            }
        }
        return false;
    }

    private String getMethodKey(ProceedingJoinPoint thisJoinPoint){
        StringBuffer keyStrBuffer = new StringBuffer();
        String classType = thisJoinPoint.getSignature().getDeclaringType().getName();
        keyStrBuffer.append(classType+".");
        String method = ((MethodSignature) thisJoinPoint.getSignature()).getMethod().getName();
        keyStrBuffer.append(method + "(");
        for (final Object arg : thisJoinPoint.getArgs()) {
            if(arg == null){
                continue;
            }
            if(arg.getClass() == null){
                keyStrBuffer.append(arg + ";");
            }else{
                keyStrBuffer.append(arg + ":" + arg.getClass().getSimpleName() + ";");
            }
        }
        keyStrBuffer.append(")");
        return keyStrBuffer.toString();
    }




}
